package com.wfh.frp.coder;

import com.wfh.frp.model.ProxyMsg;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;

/**
 * @Title: ProxyMsgDecoder
 * @Author wangfenghuan
 * @Package com.wfh.frp.coder
 * @Date 2025/10/7 20:04
 * @description: 协议解码器
 */
@Slf4j
public class ProxyMsgDecoder extends LengthFieldBasedFrameDecoder {


    public ProxyMsgDecoder() {
        super(
                1024 * 1024, // maxFrameLength
                0,           // lengthFieldOffset
                4,           // lengthFieldLength
                0,           // lengthAdjustment
                4            // initialBytesToStrip = 4 → 跳过长度头，只留 payload
        );
    }

    @Override
    protected ProxyMsg decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        ByteBuf frame = (ByteBuf) super.decode(ctx, in);
        if (frame == null || frame.readableBytes() < 4) {
            return null;
        }

        try {
            ProxyMsg msg = new ProxyMsg();

            // 1. 读 channelId
            int idLen = frame.readInt();
            if (idLen > 0) {
                if (frame.readableBytes() < idLen){
                    return null;
                }
                byte[] idBytes = new byte[idLen];
                frame.readBytes(idBytes);
                msg.setChannelId(new String(idBytes, StandardCharsets.UTF_8));
            } else if (idLen != -1) {
                throw new CorruptedFrameException("Invalid channelId length: " + idLen);
            }

            // 2. 读 dataLen
            if (frame.readableBytes() < 4){
                return null;
            }
            int dataLen = frame.readInt();

            // 3. 读 type
            if (frame.readableBytes() < 1){
                return null;
            }
            msg.setType(frame.readByte());

            // 4. 读 data
            int dataBytes = dataLen - 1;
            if (dataBytes > 0) {
                if (frame.readableBytes() < dataBytes){
                    return null;
                }
                byte[] data = new byte[dataBytes];
                frame.readBytes(data);
                msg.setData(data);
            } else if (dataBytes < 0) {
                throw new CorruptedFrameException("Invalid dataLen: " + dataLen);
            }

            log.info("msg decode: {}", msg);
            return msg;

        } finally {
            frame.release();
        }
    }
}